/*
 * Copyrignt (c) xuzeshui.com. All Rights Reserved.
 * Author: Zeshui Xu<i@xuzeshui.com>
 * Created Time: 2015-12-28 17:00:53
 * Last Modified: 2017-04-20 14:17:15
 * File Name: bdlbs/geocoding.go
 * Description:
 */

package bdlbs

import (
	"fmt"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/httplib"
	log "github.com/cihub/seelog"
)

const (
	SERVICE_GEOCODER string = "http://api.map.baidu.com/geocoder/v2/"
)

var (
	bdlbsInstance *BDLBSService
)

type LocationItem struct {
	Lat float64 `json:"lat"`
	Lng float64 `json:"lng"`
}

type AddrComponentItem struct {
	Country     string `json:"country"`      //国家
	Province    string `json:"province"`     //省份
	City        string `json:"city"`         //城市
	District    string `json:"district"`     //区县
	Street      string `json:"street"`       //街道
	Adcode      string `json:"adcode"`       //行政区编码
	CountryCode int    `json:"country_code"` //国家代码
}

//地址进行坐标解析请求
type GeoAddr2LocationReq struct {
	Address string
	City    string
}

type GeoAddr2LocationResp struct {
	Code   int                     `json:"status"`
	Msg    string                  `json:"message"`
	Result *GeoAddr2LocationResult `json:"result"`
}

type GeoAddr2LocationResult struct {
	Location   *LocationItem `json:"location"`
	Precise    int           `json:"precise"`
	Confidence int           `json:"confidence"`
	Level      string        `json:"level"`
}

func NewGeoAddr2LocationResp() *GeoAddr2LocationResp {
	obj := &GeoAddr2LocationResp{}
	obj.Result = &GeoAddr2LocationResult{}
	obj.Result.Location = &LocationItem{}
	return obj
}

//逆地址解析
type GeoLocation2AddrReq struct {
	LocationItem
	CoordType string
}

type GeoLocation2AddrResp struct {
	Code   int                     `json:"status"`
	Msg    string                  `json:"message"`
	Result *GeoLocation2AddrResult `json:"result"`
}

type GeoLocation2AddrResult struct {
	Location      *LocationItem      `json:"location"`
	FormattedAddr string             `json:"formatted_address"`
	AddrComponent *AddrComponentItem `json:"addressComponent"`
}

func NewGeoLocation2AddrResp() *GeoLocation2AddrResp {
	obj := &GeoLocation2AddrResp{}
	obj.Result = &GeoLocation2AddrResult{}
	obj.Result.Location = &LocationItem{}
	obj.Result.AddrComponent = &AddrComponentItem{}
	return obj
}

type BDLBSService struct {
	appkey string
}

func newBDLBSService() *BDLBSService {
	service := &BDLBSService{}
	service.initParams()
	return service
}

func GetBDLBSService() *BDLBSService {
	if bdlbsInstance == nil {
		bdlbsInstance = newBDLBSService()
	}
	return bdlbsInstance
}

func (p *BDLBSService) initParams() {
	p.appkey = beego.AppConfig.DefaultString("bdlbs_appkey", "")
}

/*
	根据地址解析出经纬度
*/
func (p *BDLBSService) Addr2Location(req *GeoAddr2LocationReq, resp *GeoAddr2LocationResp) error {
	b := httplib.Get(SERVICE_GEOCODER)
	b.Param("output", "json")
	b.Param("ak", p.appkey)
	b.Param("address", req.Address)
	b.Param("ret_coordtype", "bd09ll")
	if req.City != "" {
		b.Param("city", req.City)
	}
	if err := b.ToJSON(resp); err != nil {
		log.Warnf("Addr2Location error, err:%s, address: %s, city: %s", err.Error(), req.Address, req.City)
		return err
	}
	return nil
}

/*
	根据经纬度反查出地址信息
*/
func (p *BDLBSService) Location2Addr(req *GeoLocation2AddrReq, resp *GeoLocation2AddrResp) error {
	b := httplib.Get(SERVICE_GEOCODER)
	b.Param("ak", p.appkey)
	b.Param("output", "json")
	b.Param("coordtype", req.CoordType)
	b.Param("ret_coordtype", "bd09ll")
	b.Param("pois", "0")
	location := fmt.Sprintf("%f,%f", req.Lat, req.Lng)
	b.Param("location", location)
	//log.Infof("ak:%s",p.appkey)
	if err := b.ToJSON(resp); err != nil {
		log.Warnf("Location2Addr err, err: %s, lat: %f, lng: %f, coordtype: %s", err.Error(), req.Lat, req.Lng, req.CoordType)
		return err
	}
	return nil
}
